package com.lct.simpleforecast.mvp.model.network


import com.google.gson.Gson
import com.lct.simpleforecast.MyApplication
import com.lct.simpleforecast.extensions.logE
import com.lct.simpleforecast.extensions.logI
import okhttp3.*
import org.jetbrains.anko.onUiThread
import java.io.IOException

/**
 * Author：SkySmile
 * Date：2018/7/11
 * Description：OkHttp3的调用封装
 */
object OkHttp {
    const val tag = "--->OkHttp"
    const val blankDes = "返回数据为空"
    const val unknowError = "未知错误"
    const val serverError = "服务异常，请稍后重试"
    const val responseError = "响应数据格式错误"
    val okHttpClient = OkHttpClient.Builder().build()

    /**
     * GET请求
     *
     * @param url URL
     * @param callback 回调接口
     * @return Call对象，用于取消请求
     */
    inline fun <reified T : Any> doGet(url: String, callback: IRequest<T>): Call? {
        var call: Call? = null
        if (MyApplication.instance.isNetworkAvailable()) {
            //打印请求报文
            url.logI(tag)
            //发起请求，回调发生在子线程中
            val request = Request.Builder().url(url).build()
            call = okHttpClient.newCall(request)
            call.enqueue(object : Callback {
                override fun onFailure(call: Call?, e: IOException?) {
                    requestFailure(callback, e)
                }

                override fun onResponse(call: Call?, response: Response?) {
                    requestResponse(response, callback, url)
                }
            })
        } else {
            callback.onNetworkError()
        }
        return call
    }

    /**
     * POST方式提交表单
     *
     * 另有：POST方式提交String、POST方式提交流、POST方式提交文件、POST方式提交分块请求，
     * 根据实际情况进行封装
     *
     * 使用方式：val keyValues = arrayOf("key" to "value", "key2" to "value2")
     * OkHttp.doPostForm(url, request, *keyValues)
     *
     * @param url url
     * @param keyValues 键值对
     * @param callback 回调接口
     * @return Call对象，用于取消请求
     */
    inline fun <reified T : Any> doPostForm(url: String, callback: IRequest<T>,
                                            vararg keyValues: Pair<String, String>): Call? {
        var call: Call? = null
        if (MyApplication.instance.isNetworkAvailable()) {
            //请求报文
            var requestLog = "$url，params："
            //设置requestBody
            val requestBody = FormBody.Builder()
            keyValues.forEach {
                requestBody.add(it.first, it.second)
                requestLog = "$requestLog$it "
            }
            //打印请求报文
            requestLog.logI(tag)
            //发起请求
            val request = Request.Builder().url(url).post(requestBody.build()).build()
            call = okHttpClient.newCall(request)
            call.enqueue(object : Callback {
                override fun onFailure(call: Call?, e: IOException?) {
                    requestFailure(callback, e)
                }

                override fun onResponse(call: Call?, response: Response?) {
                    requestResponse(response, callback, url)
                }
            })
        } else {
            callback.onNetworkError()
        }
        return call
    }

    /**
     * 请求成功的处理
     */
    inline fun <reified T : Any> requestResponse(response: Response?, callback: IRequest<T>,
                                                 url: String) {
        //数据格式错误时打印的日志
        val errorLog = "$url $responseError" + " to ${T::class.java}"
        //获取报文，string()方法只能使用一次
        val jsonData = response?.body()?.string()
        //打印响应报文
        jsonData?.logI(tag) ?: blankDes.logI(tag)
        //解析数据，数据格式错误时Gson解析会抛出异常
        try {
            val result: T? = Gson().fromJson<T>(jsonData, T::class.java)
            //切换到主线程
            MyApplication.instance.onUiThread {
                if (result != null) {
                    callback.onSuccess(result)
                } else {
                    callback.onFailure(errorLog)
                    errorLog.logE(tag)
                }
            }
        } catch (e: Exception) {
            MyApplication.instance.onUiThread {
                callback.onFailure(errorLog)
                errorLog.logE(tag)
            }
        }
    }

    /**
     * 请求失败的处理
     */
    fun <T : Any> requestFailure(callback: IRequest<T>, e: IOException?) {
        //打印的错误日志
        val errorLog = e?.message ?: unknowError
        //切换到主线程
        MyApplication.instance.onUiThread {
            callback.onFailure(serverError)
            errorLog.logE(tag)
        }
    }
}